// types/decimal.ts
export interface DecimalCalculationResult {
  value: number;
  formatted: string;
}

export interface DecimalChain {
  add: (...numbers: number[]) => DecimalChain;
  subtract: (...numbers: number[]) => DecimalChain;
  multiply: (...numbers: number[]) => DecimalChain;
  divide: (divisor: number) => DecimalChain;
  value: () => number;
  round: (decimalPlaces?: number) => number;
  format: (decimalPlaces?: number) => string;
}

/**
 * 精确加减乘除运算工具类
 */
export class DecimalCalculator {
  /**
   * 获取小数位数
   */
  static getDecimalLength(num: number): number {
    try {
      const str = num.toString();
      if (str.includes('e')) {
        // 科学计数法处理
        const match = str.match(/(\d(?:\.(\d+))?)e([+-])(\d+)/);
        if (!match) return 0;
        const [, , fractionalStr, sign, exponent] = match;
        const fractionalLength = fractionalStr ? fractionalStr.length : 0;
        return sign === '-' ? fractionalLength + parseInt(exponent) : 0;
      }
      return str.includes('.') ? str.split('.')[1].length : 0;
    } catch {
      return 0;
    }
  }

  /**
   * 将数字转换为整数（消除小数）
   */
  static toInteger(num: number): { integer: number; times: number } {
    const decimalLength = this.getDecimalLength(num);
    const times = Math.pow(10, decimalLength);
    return { integer: Number(num.toString().replace('.', '')), times };
  }

  /**
   * 精确加法
   */
  static add(...numbers: number[]): number {
    if (numbers.length < 2) return numbers[0] || 0;
    
    return numbers.reduce((acc: number, cur: number) => {
      const maxDecimalLength = Math.max(
        this.getDecimalLength(acc),
        this.getDecimalLength(cur)
      );
      const times = Math.pow(10, maxDecimalLength);
      return (Math.round(acc * times) + Math.round(cur * times)) / times;
    });
  }

  /**
   * 精确减法
   */
  static subtract(a: number, b: number): number {
    const maxDecimalLength = Math.max(this.getDecimalLength(a), this.getDecimalLength(b));
    const times = Math.pow(10, maxDecimalLength);
    return (Math.round(a * times) - Math.round(b * times)) / times;
  }

  /**
   * 精确乘法
   */
  static multiply(...numbers: number[]): number {
    if (numbers.length < 2) return numbers[0] || 0;
    
    return numbers.reduce((acc: number, cur: number) => {
      const accDecimalLength = this.getDecimalLength(acc);
      const curDecimalLength = this.getDecimalLength(cur);
      const totalDecimalLength = accDecimalLength + curDecimalLength;
      
      const accInteger = Number(acc.toString().replace('.', ''));
      const curInteger = Number(cur.toString().replace('.', ''));
      
      return (accInteger * curInteger) / Math.pow(10, totalDecimalLength);
    });
  }

  /**
   * 精确除法
   */
  static divide(a: number, b: number): number {
    if (b === 0) throw new Error('除数不能为0');
    
    const aDecimalLength = this.getDecimalLength(a);
    const bDecimalLength = this.getDecimalLength(b);
    const maxDecimalLength = Math.max(aDecimalLength, bDecimalLength);
    
    const times = Math.pow(10, maxDecimalLength);
    return (a * times) / (b * times);
  }

  /**
   * 四舍五入到指定位数
   */
  static round(num: number, decimalPlaces: number = 2): number {
    const times = Math.pow(10, decimalPlaces);
    return Math.round(num * times) / times;
  }

  /**
   * 格式化显示
   */
  static format(num: number, decimalPlaces: number = 8): string {
    return this.round(num, decimalPlaces).toString();
  }

  /**
   * 链式计算
   */
  static chain(initialValue: number): DecimalChain {
    let result = initialValue;
    
    const chainable =  {
      add: (...numbers: number[]): DecimalChain => {
        result = this.add(result, ...numbers);
        return chainable;
      },
      
      subtract: (...numbers: number[]): DecimalChain => {
        result = numbers.reduce((acc, num) => this.subtract(acc, num), result);
        return chainable;
      },
      
      multiply: (...numbers: number[]): DecimalChain => {
        result = this.multiply(result, ...numbers);
        return chainable;
      },
      
      divide: (divisor: number): DecimalChain => {
        result = this.divide(result, divisor);
        return chainable;
      },
      
      value: (): number => result,
      
      round: (decimalPlaces: number = 2): number => {
        return this.round(result, decimalPlaces);
      },
      
      format: (decimalPlaces: number = 8): string => {
        return this.format(result, decimalPlaces);
      }
    };
    return chainable
  }
}